(() => {

    const KnowThyself = Object.create(null);

    /**
     * 获取当前脚本所在的文件, 如果是在HTML中则拿到的是HTML的地址<br/>
     * 原理: 抛出异常, 获取这个异常的栈信息, 将最底层的栈地址取出来
     * @returns {URL} url对象
     */
    KnowThyself.getImportUrl = function() {
        try {
            try {
                throw new Error('KnowThyself running...');
            } catch (e) {
                const stackLines = e.stack.split('\n');
                if (stackLines.length >= 2) {
                    const lastLine = stackLines[stackLines.length - 1];
                    const start = lastLine.indexOf('at ');
                    if (start !== -1) {
                        const end = lastLine.lastIndexOf(':', lastLine.lastIndexOf(':') - 1);
                        return new URL(lastLine.substring(start + 3, end));
                    }
                }
                return null;
            }
        } catch (e) {
            return null;
        }
    }

    /**
     * 获取当前JS文件的script元素
     * @returns 当前脚本的script元素
     */
    KnowThyself.getImportElement = function() {
        // 获取当前脚本的URL对象
        const importUrl = KnowThyself.getImportUrl();
        if (importUrl === null) {
            return null;
        }
        // 获取脚本文件的文件名, 利用文件名先进行快速的模糊匹配, 然后再解析匹配, 优化性能
        const fileName = importUrl.pathname.substring(importUrl.pathname.lastIndexOf('/') + 1);
        // 获取地址栏不带hash, search的地址信息
        const locationHref = location.origin + location.pathname;
        // 遍历页面中带有src属性的script标签, 进行文件名匹配, 再进行完整地址匹配
        for (const el of document.querySelectorAll('script[src]')) {
            const src = el.getAttribute('src');
            if (src.indexOf(fileName) !== -1) {
                const srcUrl = new URL(src, locationHref);
                if (srcUrl.toString() === importUrl.toString()) {
                    return el;
                }
            }
        }
        return null;
    }

    window.KnowThyself = KnowThyself;
})();